package parsing;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.text.html.HTMLEditorKit;

import utils.HTMLParse;

import com.smartxls.WorkBook;

public class Main {
	
	/** Map de chacun des 3 domaines (Eukarya, Archaea, Bacteria) avec une listes de genomes (réparties en différentes familles) */
	private static final Map<String,List<Genome>> bioinfo = new HashMap<String,List<Genome>>();
	
	/** Constantes des noms des dossiers */
	public static final String DOSSIER_RESULTAT = "resultats";
	public static final String DOSSIER_MODELE = "modèle";
	
	/** Site internet de la base de données */
	public static final String URL_BDD = "http://gtrnadb.ucsc.edu/";
	
	public static final String[] DATA = { "Eukarya", "Archaea", "Bacteria" };
	public static final int[] NB_PAGES = { 100, 100, 100 };
	
	private Main() {
		
	}
	
	/** Programme de parsing de la base de données en ligne : http://gtrnadb.ucsc.edu/
	 * @param args
	 */
	public static void main(String[] args) {
		
		if (!initFolderResults()) { // Crée le dossier de résultat
			Main.log("Le programme n'arrive pas à créer le dossier résultat", true);
			return;
		}
		
		new IHM("Projet de bioinformatique");
		
	}
	
	public static void start(int index) {
		readHomePage();
		
		CustomGenomeParser.init();	// Pour compiler le pattern
		String[] colNames = {"id","Famille","Espèce","Identifiant","Longueur","Type","Anticodon","Position","Seq","Str","Score"};
		
		// Initialisation du fichier Excel d'erreurs
		WorkBook wbError = new WorkBook();
		String[] colErrNames = {"id","Domaine","Famille","Espèce","Identifiant","Raison exclusion","Génome"};
		try {
			for (int i=0;i<colErrNames.length;i++) {
				wbError.setText(0, i, colErrNames[i]);
			}
			wbError.freezePanes(0, 0, 1, 0, false);
			wbError.autoFilter();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		// Parsing de chaque domaine
		if (index == 0 || index == 1) {
			domaines(colNames, wbError, DATA[0]);
		}
		if (index == 0 || index == 2) {
			domaines(colNames, wbError, DATA[1]);
		}
		if (index == 0 || index == 3) {
			domaines(colNames, wbError, DATA[2]);
		}
		
		try {
			//wbError.autoFilter();
			wbError.setColWidthAutoSize(1, true);
			wbError.setColWidthAutoSize(2, true);
			wbError.setColWidthAutoSize(3, true);
			wbError.setColWidthAutoSize(4, true);
			wbError.setColWidthAutoSize(5, true);
			wbError.writeXLSX(Main.DOSSIER_RESULTAT + File.separator + "Error.xlsx");
			wbError.dispose();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		Main.log("TERMINE", false);
	}
	
	public static void domaines(String[] colNames, WorkBook wbError, String d) {
		Main.log("\t*** BEGIN : "+d+" ***", false);
		WorkBook wb = new WorkBook();
		
		WorkBook wb_m = new WorkBook();
		try {
			wb_m.readXLSX(DOSSIER_MODELE + File.separator + "Modèle.xlsm");
			
			
			for (int i=0;i<colNames.length;i++) {
				wb.setText(0, i, colNames[i]);
				wb_m.setText(0, i, colNames[i]);
			}
			wb.freezePanes(0, 0, 1, 0, false);
			wb.autoFilter();
			wb_m.freezePanes(0, 0, 1, 0, false);
			wb_m.autoFilter();
			
			
			List<Genome> lg = bioinfo.get(d);
			for (Genome g : lg) {
				readPageGenome(d,g,wb,wb_m,wbError);
			}
			/*List<Genome> lg = bioinfo.get(d);
			for (int i=40;i<lg.size();i++) {
				readPageGenome(d,lg.get(i),wb,wbError);
			}*/
			
			Main.log("FIN DES GENOMES", false);
			
			Main.log("AVANT ECRITURE du fichier de base", false);
			wb.writeXLSX(Main.DOSSIER_RESULTAT + File.separator + d +".xlsx");
			wb.dispose();
			Main.log("APRES ECRITURE du fichier de base", false);
			Main.log("AVANT ECRITURE du fichier XLSM", false);
			wb_m.writeXLSX(Main.DOSSIER_RESULTAT + File.separator + d +".xlsm");
			wb_m.dispose();
			Main.log("APRES ECRITURE du fichier XLSM", false);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Main.log("\t*** FINISH : "+d+" ***", false);
	}
	
	/** Lecture de la page d'accueil du site internet contenant la base de données */
	public static void readHomePage() {
		// Récupération de la page d'accueil du site internet de BDD
		Main.log(URL_BDD, false);
		String res = connect(URL_BDD);
		
		// Parsing de la page d'accueil
		StringReader r = new StringReader(res);
		HTMLEditorKit.Parser parse = new HTMLParse().getParser();
		CustomHomePageParser callback = new CustomHomePageParser(bioinfo);
		try {
			parse.parse(r,callback ,true);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/** Lecture de la page des génomes du site internet contenant la base de données
	 * @param domaine
	 * @param g
	 */
	public static void readPageGenome(String domaine, Genome g, WorkBook wb, WorkBook wb_m, WorkBook wbError) {
		// Récupération de la page d'accueil du site internet de BDD
		Main.log(g.getUrl().toString(), false);
		String res = connect(g.getUrl().toString());

		// Parsing de la page des génomes
		StringReader r = new StringReader(res);
		HTMLEditorKit.Parser parse = new HTMLParse().getParser();
		CustomGenomeParser callback = null;
		try {
			callback = new CustomGenomeParser(domaine, g, wb, wb_m, wbError);
			parse.parse(r, callback, true);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/** Se connecte à une page web et renvoie le code source ou l'enregistre dans un fichier
	 * @param adresse :  adresse de la page web
	 * @param isFile : enregistrement de la page web dans un fichier ou pas
	 * @param nameFiledownload : si isFile est true, on enregistre dans name_download
	 * @return
	 */
	public static String connect(String adresse) {
		String rep=null;
		BufferedReader in=null;
		URL site;
		try {
			site = new URL(adresse);
			HttpURLConnection httpcon = (HttpURLConnection)site.openConnection();
			httpcon.setUseCaches(false);
			httpcon.connect();
			if(httpcon.getResponseCode()!=HttpURLConnection.HTTP_OK) {// échec de la connection
				Main.log("Connection HTTP : erreur\n"+httpcon.getResponseMessage(), true);
			} else {// Lecture de la réponse
				//System.out.println("Connection HTTP : réussi      |     Réponse="+httpcon.getResponseCode());
				
				in = new BufferedReader(new InputStreamReader(httpcon.getInputStream()));
				StringBuffer s = new StringBuffer();
				String inputLine;
				while ((inputLine = in.readLine()) != null) {
					s.append(inputLine.replaceAll("<<", "&lt;&lt;").replaceAll("<\\.", "&lt;.").replaceAll("<>", "&lt;>"));
					s.append("\n");
				}
				rep = s.toString();
			}
			httpcon.disconnect();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		finally {
			if (in!=null) {
				try {
					in.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
				}
			}
		}
		return rep;
	}
	
	/** Initialisation du dossier contenant les fichiers résultats
	 * @return : si la création du dossier c'est bien passé
	 */
	public static boolean initFolderResults() {
		// Création du dossier si inexistant
		File d = new File(Main.DOSSIER_RESULTAT);
		boolean dossierOk = true;
		
		if (!d.exists()) {
			// si le dossier n'existe pas, on le crée
			dossierOk = d.mkdir();
		}
		
		return dossierOk;
	}
	
	public static void log(String message, boolean isError) {
		SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
		Calendar cal = Calendar.getInstance();
		Date d = new Date();
		cal.setTime(d);
		StringBuffer msg = new StringBuffer();
		
		msg.append(dateFormat.format(cal.getTime()));
		msg.append(" ");
		msg.append(message);
		
		if (isError) {
			System.err.println(msg);
		}
		else {
			System.out.println(msg);
		}
	}
}